package org.fhawk.tinyspring.aop;

import org.fhawk.tinyspring.InstantFactory;
import org.fhawk.tinyspring.aop.annotation.Aspect;
import org.fhawk.tinyspring.aop.proxy.Proxy;
import org.fhawk.tinyspring.aop.proxy.ProxyManaggerFactory;
import org.fhawk.tinyspring.core.ClassHelper;
import org.fhawk.tinyspring.core.ClassScanner;
import org.fhawk.tinyspring.ioc.BeanHelper;
import org.fhawk.tinyspring.tx.TransactionProxy;
import org.fhawk.tinyspring.tx.annotation.Transaction;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

import static org.fhawk.tinyspring.core.ClassHelper.getBasePackageClassListByAnnotation;

/**
 * 代理处理类
 *
 * @author fhawk
 * @since jdk 1.8+
 */
@SuppressWarnings("unchecked")
public class AopHelper {
    private static ClassScanner scanner = InstantFactory.getClassScanner();
    private static Logger logger = LoggerFactory.getLogger(AopHelper.class);
    private static final Class<Proxy> PROXY_CLASS = Proxy.class;

    private AopHelper() {
    }

    static {
        Map<Class<? extends Proxy>, List<Class<?>>> proxyMap = createProxyMap();
        Map<Class<?>, List<Class<? extends Proxy>>> classProxyMap = createClassProxyMap(proxyMap);
        for (Map.Entry<Class<?>, List<Class<? extends Proxy>>> entry : classProxyMap.entrySet()) {
            Class<?> key = entry.getKey();
            List<Class<? extends Proxy>> value = entry.getValue();
            BeanHelper.setBean(key, ProxyManaggerFactory.newInstance(key, value));
        }
    }

    /**
     * 代理类和原类的匹配
     *
     * @param proxyMap 代理类和类数组
     * @return 匹配后的组合
     */
    private static Map<Class<?>, List<Class<? extends Proxy>>> createClassProxyMap(Map<Class<? extends Proxy>, List<Class<?>>> proxyMap) {
        Map<Class<?>, List<Class<? extends Proxy>>> map = new HashMap<>();
        for (Map.Entry<Class<? extends Proxy>, List<Class<?>>> entry : proxyMap.entrySet()) {
            Class<? extends Proxy> key = entry.getKey();
            List<Class<?>> value = entry.getValue();
            for (Class<?> clazz : value) {
                if (map.containsKey(clazz)) {
                    map.get(clazz).add(key);
                } else {
                    List<Class<? extends Proxy>> proxies = new ArrayList<>();
                    proxies.add(key);
                    map.put(clazz, proxies);
                }
            }
        }
        return map;
    }

    /**
     * 创建所有代理（AOP,事务）
     *
     * @return 代理类map
     */

    private static Map<Class<? extends Proxy>, List<Class<?>>> createProxyMap() {
        Map<Class<? extends Proxy>, List<Class<?>>> map = new HashMap<>();
        addAopProxyMap(map);
        addTransactionMap(map);
        return map;
    }

    /**
     * 所有需要事务处理的类代理
     *
     * @param map 所有代理
     */
    private static void addTransactionMap(Map<Class<? extends Proxy>, List<Class<?>>> map) {
        List<Class<?>> classes = ClassHelper.getBasePackageClassListByAnnotation(Transaction.class).stream()
            .filter(clazz -> clazz.getInterfaces().length > 0).collect(Collectors.toList());
        map.put(TransactionProxy.class, classes);
    }

    /**
     * AOP 代理类和类的获取
     *
     * @param map 所有代理类
     */
    private static void addAopProxyMap(Map<Class<? extends Proxy>, List<Class<?>>> map) {
        List<Class<?>> list = getBasePackageClassListByAnnotation(Aspect.class);
        for (Class<?> clazz : list) {
            logger.debug("自定义AOP:{} 解析", clazz);
            String packageName = clazz.getAnnotation(Aspect.class).pkg();
            List<Class<?>> aopClass = scanner.getAllImplClassWithoutInterface(packageName);
            if (PROXY_CLASS.isAssignableFrom(clazz)) {
                map.put((Class<? extends Proxy>) clazz, aopClass);
            } else {
                logger.error("类{}添加注解{}，则必须实现类{}", clazz, Aspect.class, PROXY_CLASS);
            }
        }
    }
}
